package com.ylr.admin.framework.service.impl;

import com.ylr.admin.common.dto.uri.UriDto;
import com.ylr.admin.common.dto.uri.UriEnumDto;
import com.ylr.admin.common.enums.UriEnum;
import com.ylr.admin.common.vo.uri.UriFormVo;
import com.ylr.admin.common.vo.uri.UriVo;
import com.ylr.admin.framework.entity.UriEntity;
import com.ylr.admin.framework.mapper.UriMapper;
import com.ylr.admin.framework.service.UriService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylr.base.common.constant.Constant;
import com.ylr.base.common.dto.PageDto;
import com.ylr.base.common.enums.CommonEnum;
import com.ylr.base.common.enums.ModuleEnum;
import com.ylr.base.common.enums.ResultEnum;
import com.ylr.base.common.exception.YlrException;
import com.ylr.base.common.po.user.UserPo;
import com.ylr.base.common.utils.ThrottleUtils;
import com.ylr.base.common.utils.UserUtils;
import com.ylr.base.common.vo.UpdateStatusVo;
import com.ylr.base.framework.service.AsyncService;
import com.ylr.base.framework.service.SnowflakeService;
import com.ylr.config.common.enums.KeyEnum;
import com.ylr.config.framework.resolver.YcMappingResolver;
import com.ylr.redis.framework.service.RedisService;
import com.ylr.redis.framework.service.RedisStringService;
import com.ylr.redis.framework.service.RedissonService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-04-21 11:44:34
 * className: UriServiceImpl
 * version: 1.0
 * description:
 */
@Service("uriService")
@AllArgsConstructor
public class UriServiceImpl extends ServiceImpl<UriMapper, UriEntity> implements UriService {

    private static final Logger log = LoggerFactory.getLogger(UriServiceImpl.class);

    private final YcMappingResolver ycMappingResolver;

    private final SnowflakeService snowflakeService;

    private final AsyncService asyncService;

    private final RedisStringService redisStringService;

    private final RedisService redisService;

    private final RedissonService redissonService;

    private final ThrottleUtils throttleUtils;

    @Override
    public void saveUri(UriVo uriVo) {

        // 获取正在保存系统接口的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        UriEntity uri = this.getUri(uriVo, userPo, date);
        // 插入数据
        baseMapper.insert(uri);
        log.info("系统接口插入完成");

        // 删除缓存
//        this.deleteCache(Collections.singletonList(uri.getType()));
    }

    @Transactional
    @Override
    public void batchSaveUri(List<UriVo> uriVoList) {

        // 获取正在保存系统接口的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        List<UriEntity> uriList = new ArrayList<>(uriVoList.size());
        for (UriVo uriVo : uriVoList) {
            UriEntity uri = this.getUri(uriVo, userPo, date);
            uriList.add(uri);
        }

        // 批量插入数据
        this.saveBatch(uriList);
        log.info("系统接口批量插入完成");

        // 删除缓存
//        this.deleteCache(Collections.singletonList(uri.getType()));
    }

    @Override
    public PageDto<UriDto> pageUriList(UriFormVo uriFormVo) {

        LambdaQueryWrapper<UriEntity> uriLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 匹配条件
        uriLambdaQueryWrapper.eq(Objects.nonNull(uriFormVo.getParentId()), UriEntity::getParentId, uriFormVo.getParentId())
                .eq(Objects.nonNull(uriFormVo.getModule()), UriEntity::getModule, uriFormVo.getModule())
                .eq(Objects.nonNull(uriFormVo.getType()), UriEntity::getType, uriFormVo.getType())
                .eq(Objects.nonNull(uriFormVo.getCheckMode()), UriEntity::getCheckMode, uriFormVo.getCheckMode())
                .eq(Objects.nonNull(uriFormVo.getLabel()), UriEntity::getLabel, uriFormVo.getLabel())
                .eq(Objects.nonNull(uriFormVo.getStatus()), UriEntity::getStatus, uriFormVo.getStatus())
                .eq(StringUtils.isNotBlank(uriFormVo.getWord()), UriEntity::getUriName, uriFormVo.getWord())
                .eq(StringUtils.isNotBlank(uriFormVo.getUri()), UriEntity::getUri, uriFormVo.getUri())
                .eq(UriEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 查询数据
        List<UriEntity> uriList = baseMapper.selectList(uriLambdaQueryWrapper);
        if (uriList.isEmpty()) {
            log.info("匹配到结果为空");
            return new PageDto<>();
        }

        List<UriDto> uriDtoList = new ArrayList<>();
        Map<String, UriDto> uriMap = new HashMap<>();
        List<UriDto> lastOptList = new ArrayList<>();
        for (UriEntity uri : uriList) {
            // 数据封装
            UriDto uriDto = this.getUriDto(uri);

            uriMap.put(uriDto.getId(), uriDto);

            // 查找父接口
            UriDto parentUriDto = uriMap.get(uriDto.getParentId());
            if (Objects.isNull(parentUriDto)) {
                if (CommonEnum.DEFAULT_ID.getStringValue().equals(uriDto.getParentId())) {
                    // 一级接口
                    uriDtoList.add(uriDto);
                    continue;
                }
                // 找不到父级接口，延后处理
                lastOptList.add(uriDto);
            }
            parentUriDto.getChildren().add(uriDto);
        }
        for (UriDto uriDto : lastOptList) {
            // 查找父接口
            UriDto parentUriDto = uriMap.get(uriDto.getParentId());
            if (Objects.isNull(parentUriDto)) {
                // 仍未找到父接口，直接加到结果列表中
                uriDtoList.add(uriDto);
                continue;
            }
            parentUriDto.getChildren().add(uriDto);
        }
        uriDtoList.sort(Comparator.comparing(UriDto::getSort).thenComparing(UriDto::getCreateTime).thenComparing(UriDto::getId));

        // 分页操作
        return PageDto.pageDtoBuild(uriDtoList, uriFormVo.getPageNo(), uriFormVo.getPageSize());
    }

    @Override
    public UriDto getUri(Long id) {
        // 查询数据
        UriEntity uri = baseMapper.selectById(id);
        if (Objects.isNull(uri)) {
            log.warn("系统接口不存在");
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
        if (CommonEnum.DELETE_YES.getValue().equals(uri.getDeleteStatus())) {
            log.warn("系统接口已被删除");
            throw new YlrException(ResultEnum.NOT_FOUND);
        }

        return this.getUriDto(uri);
    }

    @Override
    public Integer getNextSort(Long parentId) {
        // 查询数据
        Integer maxSort = baseMapper.selectMaxSort(parentId, CommonEnum.DELETE_NO.getValue());
        if (Objects.isNull(maxSort)) {
            maxSort = 0;
        }
        return maxSort + 1;
    }

    @Override
    public List<UriDto> getPacket(Long parentId) {

        UriDto parentUri = null;
        if (Objects.nonNull(parentId)) {
            LambdaQueryWrapper<UriEntity> uriLambdaQueryWrapper = new LambdaQueryWrapper<>();
            // 查询字段
            uriLambdaQueryWrapper.select(UriEntity::getId, UriEntity::getParentId, UriEntity::getParentPath, UriEntity::getUriName,
                    UriEntity::getSort, UriEntity::getCreateTime);
            // 匹配条件
            uriLambdaQueryWrapper.eq(UriEntity::getId, parentId)
                    .eq(UriEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
            // 查询数据
            List<UriEntity> uriList = baseMapper.selectList(uriLambdaQueryWrapper);
            if (uriList.isEmpty()) {
                log.warn("父级接口数据不存在");
                throw new YlrException(ResultEnum.NOT_FOUND);
            }
            parentUri = this.getUriDto(uriList.get(0));
        }

        LambdaQueryWrapper<UriEntity> uriLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        uriLambdaQueryWrapper.select(UriEntity::getId, UriEntity::getParentId, UriEntity::getParentPath, UriEntity::getUriName,
                UriEntity::getSort, UriEntity::getCreateTime);
        // 匹配条件
        uriLambdaQueryWrapper.likeRight(Objects.nonNull(parentUri), UriEntity::getParentPath, parentUri.getParentPath() + parentUri.getId() + Constant.SPLIT)
                .eq(UriEntity::getType, UriEnum.PACKET_TYPE.getValue())
                .eq(UriEntity::getStatus, CommonEnum.STATUS_USE.getValue())
                .eq(UriEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 查询数据
        List<UriEntity> uriList = baseMapper.selectList(uriLambdaQueryWrapper);
        if (uriList.isEmpty()) {
            log.info("子接口数据为空");
            return Collections.emptyList();
        }

        Map<String, UriDto> uriMap = new HashMap<>();
        List<UriDto> lastOptList = new ArrayList<>();

        uriMap.put(parentUri.getId(), parentUri);

        for (UriEntity uri : uriList) {
            // 数据封装
            UriDto uriDto = this.getUriDto(uri);

            uriMap.put(uriDto.getId(), uriDto);

            // 查找父接口
            UriDto parentUriDto = uriMap.get(uriDto.getParentId());
            if (Objects.isNull(parentUriDto)) {
                // 找不到父级接口，延后处理
                lastOptList.add(uriDto);
            }
            parentUriDto.getChildren().add(uriDto);
        }
        for (UriDto uriDto : lastOptList) {
            // 查找父接口
            UriDto parentUriDto = uriMap.get(uriDto.getParentId());
            if (Objects.isNull(parentUriDto)) {
                log.warn("父级接口找不到。{}", uriDto);
                continue;
            }
            parentUriDto.getChildren().add(uriDto);
        }

        return Collections.singletonList(parentUri);
    }

    @Override
    public UriEnumDto getPageEnums() {

        UriEnumDto uriEnumDto = new UriEnumDto();
        uriEnumDto.setModuleEnumList(ModuleEnum.getModuleEnumList(ModuleEnum.GATEWAY.getValue()));
        uriEnumDto.setTypeEnumList(UriEnum.getTypeEnumList());
        uriEnumDto.setCheckModeEnumList(UriEnum.getCheckModeEnumList());
        uriEnumDto.setLabelEnumList(UriEnum.getLabelEnumList());
        uriEnumDto.setStatusEnumList(CommonEnum.getStatusEnumList());

        return uriEnumDto;
    }

    @Override
    public void updateUri(UriVo uriVo) {

        // 获取正在修改系统接口的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        UriEntity uri = new UriEntity();
        uri.setId(uriVo.getId())
            .setParentId(uriVo.getParentId())
            .setParentPath(uriVo.getParentPath() + uriVo.getParentId() + Constant.SPLIT)
            .setModule(uriVo.getModule())
            .setUriName(uriVo.getUriName())
            .setUri(uriVo.getUri())
            .setPermit(Optional.ofNullable(uriVo.getPermit()).orElse(StringUtils.EMPTY))
            .setType(uriVo.getType())
            .setCheckMode(uriVo.getCheckMode())
            .setLabel(uriVo.getLabel())
            .setRemark(Optional.ofNullable(uriVo.getRemark()).orElse(StringUtils.EMPTY))
            .setUpdateTime(date)
            .setUpdateUser(userPo.getUsername())
            .setUpdateUserId(userPo.getId());
        // 修改数据
        int count = baseMapper.updateById(uri);
        log.info("系统接口修改完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }

    }

    @Override
    public void updateUriStatus(UpdateStatusVo updateStatusVo) {

        // 获取正在修改’系统接口‘状态的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        LambdaUpdateWrapper<UriEntity> uriLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置字段值
        uriLambdaUpdateWrapper.set(UriEntity::getStatus, updateStatusVo.getStatus())
                .set(UriEntity::getUpdateTime, date)
                .set(UriEntity::getUpdateUser, userPo.getUsername())
                .set(UriEntity::getUpdateUserId, userPo.getId());
        // 匹配条件
        uriLambdaUpdateWrapper.in(UriEntity::getId, updateStatusVo.getIdList())
                .eq(UriEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 更新数据
        int count = baseMapper.update(null, uriLambdaUpdateWrapper);
        log.info("修改’系统接口‘状态完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }

    }

    @Override
    public void deleteUri(List<Long> idList) {

        // 校验删除数量是否超过最大阈值
        Integer batchMax = ycMappingResolver.getValue(KeyEnum.BATCH_OPT_NUM.getKey(), Integer.class);
        if (batchMax < idList.size()) {
            log.warn("一次删除接口数量超过阈值。batchMax={} idListSize={}", batchMax, idList.size());
            throw new YlrException(ResultEnum.BATCH_FAIL);
        }

        // 获取正在删除’系统接口‘状态的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        LambdaUpdateWrapper<UriEntity> uriLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置字段值
        uriLambdaUpdateWrapper.set(UriEntity::getDeleteStatus, CommonEnum.DELETE_YES.getValue())
                .set(UriEntity::getUpdateTime, date)
                .set(UriEntity::getUpdateUser, userPo.getUsername())
                .set(UriEntity::getUpdateUserId, userPo.getId());
        // 匹配条件
        uriLambdaUpdateWrapper.in(UriEntity::getId, idList)
                .eq(UriEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 更新数据
        int count = baseMapper.update(null, uriLambdaUpdateWrapper);
        log.info("删除’系统接口‘完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }

    }

    /**
     * 获取系统接口对象
     * @param uriVo  参数对象
     * @param userPo 操作用户对象
     * @param date   日期对象
     * @return 枚举配置对象
     */
    private UriEntity getUri(UriVo uriVo, UserPo userPo, Date date) {
        UriEntity uri = new UriEntity();
        uri.setId(snowflakeService.getId())
            .setParentId(uriVo.getParentId())
            .setParentPath(uriVo.getParentPath() + uriVo.getParentId() + Constant.SPLIT)
            .setModule(uriVo.getModule())
            .setUriName(uriVo.getUriName())
            .setUri(uriVo.getUri())
            .setPermit(Optional.ofNullable(uriVo.getPermit()).orElse(StringUtils.EMPTY))
            .setType(uriVo.getType())
            .setCheckMode(uriVo.getCheckMode())
            .setLabel(uriVo.getLabel())
            .setRemark(Optional.ofNullable(uriVo.getRemark()).orElse(StringUtils.EMPTY))
            .setStatus(CommonEnum.STATUS_USE.getValue())
            .setDeleteStatus(CommonEnum.DELETE_NO.getValue())
            .setUpdateTime(date)
            .setUpdateUser(userPo.getUsername())
            .setUpdateUserId(userPo.getId())
            .setCreateTime(date)
            .setCreateUser(userPo.getUsername())
            .setCreateUserId(userPo.getId());
        return uri;
    }

    /**
     * 封装系统接口返回结果
     * @param uri 系统接口对象
     * @return 封装结果
     */
    private UriDto getUriDto(UriEntity uri) {
        UriDto uriDto = new UriDto();
        uriDto.setId(uri.getId().toString())
                .setParentId(uri.getParentId().toString())
                .setParentPath(uri.getParentPath())
                .setModule(uri.getModule())
                .setName(uri.getUriName())
                .setUri(uri.getUri())
                .setPermit(uri.getPermit())
                .setType(uri.getType())
                .setCheckMode(uri.getCheckMode())
                .setLabel(uri.getLabel())
                .setSort(uri.getSort())
                .setRemark(uri.getRemark())
                .setStatus(uri.getStatus())
                .setUpdateTime(uri.getUpdateTime())
                .setUpdateUser(uri.getUpdateUser())
                .setCreateTime(uri.getCreateTime())
                .setCreateUser(uri.getCreateUser())
                .setChildren(new TreeSet<>());
        return uriDto;
    }

    /**
     * 删除缓存
     * 根据枚举类型，删除对应缓存数据
     * @param typeList 枚举类型数组
     */
//    private void deleteCache(Collection<Integer> redisKeyList) {
//        // 删除缓存
//        redisService.delete(redisKeyList);
//        asyncService.schedule(() -> {
//            // 延迟双删
//            redisService.delete(redisKeyList);
//        }, 1500, TimeUnit.MILLISECONDS);
//    }
}